using System;
using System.Collections;
using System.Text;
using System.Net.Sockets;
using System.IO;
using System.Threading;
using System.Windows.Forms;
using System.Drawing;
using System.Net;

namespace MSNClient
{
    public delegate void StateChangeDelegate(object sender, EventArgs e);
    public delegate void MessageReceiveDelegate(object sender, MessageData message);
    public delegate void ContactListReceiveedDelegate(object sender, ContactInfo[] users);
    public delegate void UserInfoUpdateDelegate(object sender, UserStatusInfo users);

    /*
     * Here Begins Main part of MSN protocol.
     * 
     */
    //MSPAuth and MSPProf
    struct TicketData
    {
        public String MSPAuth;
        public String MSPProf;
    }

    public enum MsgType
    {
        Message,
        Nudge,
        Join
    }
    public class MsnClient
    {
        /// <summary>
        /// Debug write debug data to file
        /// </summary>
        /// 


        //Ticket data Needed for Coockie in Seervices
        TicketData iTicketData;
        public static bool WriteDebugDataToFile = false;
        public UserStatus currentUserStatus = UserStatus.Offline;

        ArrayList iOpenedSessions = new ArrayList(); //Used for storing all connection which was made for additional purposes (Chat Session)
        SocketState iMainSocketState = SocketState.Disconnected;
        MsnClient_SOAP iMsnSoap = new MsnClient_SOAP();
        public event StateChangeDelegate OnStateChangedEvent;
        public event MessageReceiveDelegate OnMessageReceiveEvent;
        /// <summary>
        /// It occurs every time when we must update contact list
        /// </summary>
        public event ContactListReceiveedDelegate OnContactListReceiveEvent;
        /// <summary>
        /// Is is occurs if user changed you status, display name or tagName
        /// </summary>
        public event UserInfoUpdateDelegate OnUserInfoUpdateEvent;

        public static String iMsnAddress = "messenger.hotmail.com"; //Address of msn server
        private const string iMsnClientVersion = "14.0.8064.0206";
        public static int iMsnPort = 1863;
        private IPAddress iMsnAddressIP = IPAddress.None; //Ip address of MSN server.

        private SocketWrapper iMainSocketWrapper;
        //private SocketWrapper iMsgSocket; //Socket for Messages;
        /************/

        private String iLogin = "";
        private String iPassword = "";

        public String iMessage = "";

        public String iMSPAuth = ""; //Cookies;        
        public static int iTransactID = 1;//Transaction ID
        public static bool _FinSess = false;
        public static bool iAuthCompleted = false;
        private String iDataSend = "";

        private bool iAllDataReceived = true;
        //For temp use later will be removed.
        private String userToJoin = "";
        private String dataToSend = "";

        /*
         * For Recievind a big amount of data
         */
        private int iLargeDataSize = 0;
        private String iLargeDataStore = "";
        //if in header DALogin = value then WHAT must be DALogin
        //if type true returns only value
        //if false returns all including DALogin

        /// <summary>
        /// Stores contact list,
        /// </summary>
        ContactInfo[] contactListData;
        bool contactListHaveData = false;
        public MsnClient()
        {
            OnStateChangedEvent += new StateChangeDelegate(OnStateChanged);
            //OnMessageReceiveEvent += new MessageReceiveDelegate(OnMessageReceive);
        }

        private void CloseMessageSessions()
        {
            for (int i = 0; i < this.iOpenedSessions.Count; i++)
            {
                SocketWrapper wrapper = (SocketWrapper)this.iOpenedSessions[i];
                wrapper.state = SocketState.Disconnected;
                wrapper.socket.Close();
                this.iOpenedSessions.RemoveAt(i);
            }
        }

        public void Connect()
        {
            if (iMainSocketState == SocketState.Disconnected)
            {
                Console.WriteLine("Connecting...");
                try
                {
                    if (iMsnAddressIP == IPAddress.None)
                    {
                        //Resolving host to ip
                        IPHostEntry IpHAddress = Dns.GetHostEntry(iMsnAddress);
                        IPAddress[] ipAddress = IpHAddress.AddressList;
                        iMsnAddressIP = ipAddress[0];
                    }
                    //begining connect
                    iMainSocketWrapper = new SocketWrapper(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                    iMainSocketWrapper.socket.BeginConnect(iMsnAddressIP, iMsnPort, ConnectionCompleted, iMainSocketWrapper);
                    iTransactID = 1;
                }
                catch (SocketException e)
                {
                    Console.WriteLine("Socket Error:" + e.NativeErrorCode);
                    Console.WriteLine(e.Message);
                }
            }
        }
        //For checking curent state of conection
        public SocketState CheckStatus(SocketWrapper aSocketWrapper)
        {
            if (aSocketWrapper.IsConnected())
                return SocketState.Connected;
            return SocketState.Disconnected;


        }
        protected void ConnectionCompleted(IAsyncResult result)
        {
            try
            {
                ((SocketWrapper)result.AsyncState).socket.EndConnect(result);
                Console.WriteLine("Connected");
                Console.WriteLine("Socket successfully connected to " + iMsnAddressIP.ToString());
                iMainSocketWrapper.state = SocketState.Connected;
                iMainSocketState = SocketState.Connected;
                OnStateChangedEvent.Invoke(this, EventArgs.Empty);
                iMainSocketWrapper.socket.BeginReceive(iMainSocketWrapper.iReceiveBuffer, 0, iMainSocketWrapper.Buffer_Size, SocketFlags.None, DataReceived_Callback, iMainSocketWrapper);
                SecondPhaseConnection();
            }
            catch (SocketException se)
            {
                Console.WriteLine("Error:{0}", se.ErrorCode);
                Console.WriteLine(se.Message);
            }

        }
        private void SecondPhaseConnection()
        {

            iDataSend = "VER " + iTransactID + " MSNP15 MSNP14 MSNP13 CVR0\r\n";
            SendData(iDataSend, iMainSocketWrapper);


        }
        public bool SendData(String aData, String aAccountName)
        {
            SocketWrapper socketWrapperPtr = GetSocketWrapperObject(aAccountName);
            if (socketWrapperPtr != null && socketWrapperPtr.IsConnected())
            {
                SendData(MessageData.GreateMessage(aData, iTransactID), socketWrapperPtr);
                return true;
            }
            else
            {
                SendData("XFR " + iTransactID + " SB\r\n", iMainSocketWrapper);
                userToJoin = aAccountName;
                dataToSend = aData;
                return true;
            }
        }
        public void SendData(String aData, SocketWrapper aSocketWrapper)
        {
            if (aSocketWrapper.state == SocketState.Connected)
            {
                try
                {
                    aSocketWrapper.socket.BeginSend(Encoding.UTF8.GetBytes(aData), 0, Encoding.UTF8.GetBytes(aData).Length, SocketFlags.None, new AsyncCallback(this.DataSend_Callback), aSocketWrapper);
                    iTransactID++;
                    if (!aData.EndsWith("\r\n"))
                    {
                        aData = aData + "\r\n";
                    }
                    Console.WriteLine("Client:" + aData);
                }
                catch (SocketException exception)
                {
                    Console.WriteLine(exception.Message);
                    Console.WriteLine("SendData error: " + exception.NativeErrorCode);
                    aSocketWrapper.state = SocketState.Disconnected;
                    aSocketWrapper.error = exception.NativeErrorCode;
                    aSocketWrapper.socket.Close();
                    if ((aSocketWrapper.accountName != "") && aSocketWrapper.accountName.Contains("@"))
                    {
                        this.iOpenedSessions.Remove(aSocketWrapper);
                    }
                }
                catch (Exception exception2)
                {
                    Console.WriteLine("SendData Error: " + exception2.Message);
                    Console.WriteLine(exception2.StackTrace);
                }
            }

        }

        public bool SendData(string aData, string aAccountName, MsgType aType)
        {
            SocketWrapper socketWrapperObject = this.GetSocketWrapperObject(aAccountName);
            if ((socketWrapperObject != null) && socketWrapperObject.IsConnected())
            {
                if (aType == MsgType.Nudge)
                {
                    this.SendData(MessageData.GreateNudge(iTransactID), socketWrapperObject);
                }
                else if (aType == MsgType.Message)
                {
                    this.SendData(MessageData.GreateMessage(aData, iTransactID), socketWrapperObject);
                }
                return true;
            }
            this.SendData("XFR " + iTransactID + " SB\r\n", this.iMainSocketWrapper);
            this.userToJoin = aAccountName;
            this.dataToSend = aData;
            return true;
        }

        protected void DataSend_Callback(IAsyncResult result)
        {
            ((SocketWrapper)result.AsyncState).socket.EndSend(result);
        }
        /*
         * Processing commands
         */
        private void ProcessReceiveData(SocketWrapper aSocketWrapper)
        {
            if (aSocketWrapper.lastCommand == Commands.XFR)
            {
                if (aSocketWrapper.iDataReceive.Split(' ')[2] == "NS")
                {
                    Disconnect();
                    iMsnAddressIP = GetIPFromCommand(aSocketWrapper.lastCommand, aSocketWrapper.iDataReceive);
                    if (iMsnAddressIP != IPAddress.None)
                    {
                        Console.WriteLine("New ip->" + iMsnAddressIP.ToString());
                        Connect();
                    }
                    else
                    {
                        Console.WriteLine("Incorrect IP:" + aSocketWrapper.iDataReceive);
                    }
                }
                else if (aSocketWrapper.iDataReceive.Split(' ')[2] == "SB")
                {
                    SocketWrapper msgSocketWrapper = new SocketWrapper(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                    if (GetIPFromCommand(Commands.XFR, aSocketWrapper.iDataReceive) != IPAddress.None)
                    {
                        String ticket = aSocketWrapper.iDataReceive.Split(' ')[5];
                        iOpenedSessions.Add(msgSocketWrapper);
                        msgSocketWrapper.accountName = "NULL";
                        msgSocketWrapper.socket.Connect(GetIPFromCommand(aSocketWrapper.lastCommand, aSocketWrapper.iDataReceive), iMsnPort);
                        msgSocketWrapper.state = SocketState.Connected;
                        SendData("USR " + iTransactID + " " + iLogin + " " + ticket + "\r\n", msgSocketWrapper);
                        msgSocketWrapper.socket.BeginReceive(msgSocketWrapper.iReceiveBuffer, 0, msgSocketWrapper.Buffer_Size, SocketFlags.None, DataReceived_Callback, msgSocketWrapper);
                    }
                }

            }
            else if (aSocketWrapper.lastCommand == Commands.VER)
            {
                iDataSend = "CVR " + iTransactID + " 0x0409 winnt 5.1 i386 MSNMSGR "+iMsnClientVersion+" MSMSGS " + iLogin + "\r\n";
                SendData(iDataSend, aSocketWrapper);
                iDataSend = "USR " + iTransactID + " TWN I " + iLogin + "\r\n";
                SendData(iDataSend, aSocketWrapper);
            }

            #region USR Command
            /*
                 * USR
                 */
            else if (aSocketWrapper.lastCommand == Commands.USR)
            {
                if (aSocketWrapper.iDataReceive.Split(' ').Length > 2 && aSocketWrapper.iDataReceive.Split(' ')[2] == "TWN")
                {
                    Console.WriteLine("Getting Twener auth");
                    String twnData = aSocketWrapper.iDataReceive.Split(' ')[4].TrimEnd();
                    Console.WriteLine("Twm:" + twnData);
                    String ticket = iMsnSoap.GetTicket(iLogin, iPassword, twnData);
                    iDataSend = "USR " + iTransactID + " TWN S t=" + ticket + "\r\n";
                    SendData(iDataSend, aSocketWrapper);

                    //Getting MSPAuth and MSPProf
                    String[] data = ticket.Split(new string[] { "&p=" }, StringSplitOptions.None);
                    if (data.Length == 2)
                    {
                        iTicketData.MSPAuth = data[0];
                        iTicketData.MSPProf = data[1];
                        Console.WriteLine("MSPAuth:" + iTicketData.MSPAuth);
                        Console.WriteLine("MSPProf:" + iTicketData.MSPProf);
                    }
                    else
                    {
                        Console.WriteLine("Error getting MSPAuth and MSPProf:" + ticket);
                    }
                }
                else if (aSocketWrapper.iDataReceive.Split(' ').Length > 2 && aSocketWrapper.iDataReceive.Split(' ')[2] == "OK")
                {
                    if (aSocketWrapper.accountName == "NULL")
                    {
                        aSocketWrapper.accountName = userToJoin;
                        SendData("CAL " + iTransactID + " " + userToJoin + "\r\n", aSocketWrapper);
                    }
                    Console.WriteLine("Authentication Completed!");
                    iAuthCompleted = true;
                }
            }
            #endregion

            /*
         * GCF
         */
            else if (aSocketWrapper.lastCommand == Commands.GCF)
            {
            }
            /*
             * Return SBS 0 null
             */
            else if (aSocketWrapper.lastCommand == Commands.SBS)
            {
                int lineEndIndex = aSocketWrapper.iDataReceive.IndexOf("\r\n");
                if (aSocketWrapper.iDataReceive.Substring(lineEndIndex).Contains("MSG"))
                {
                    aSocketWrapper.iDataReceive = aSocketWrapper.iDataReceive.Substring(lineEndIndex).TrimStart();
                    Commands newCommand = GetNewCommand(aSocketWrapper.iDataReceive);
                    if (newCommand != Commands.NONE)
                    {
                        aSocketWrapper.lastCommand = newCommand;
                    }
                    ProcessReceiveData(aSocketWrapper);
                }
            }
            //Processed all MSG commands;
            else if (aSocketWrapper.lastCommand == Commands.MSG)
            {
                if (MSNClient_Data.GetContentType(aSocketWrapper.iDataReceive) == "text/x-msmsgsprofile;")
                {
                    iMSPAuth = GetMSPAuth(aSocketWrapper.iDataReceive);
                    if (WriteDebugDataToFile)
                    {
                        WriteToFile("C:\\Documents and Settings\\" + Environment.UserName + "\\Desktop\\Msn_Client_Debug_Data\\mspauth.txt", iMSPAuth + "<");
                    }

                    Console.WriteLine("Getting ContactList......");
                    contactListData = iMsnSoap.GetContactList(iTicketData);
                    if (contactListData != null)
                    {
                        contactListHaveData = true;
                        currentUserStatus = UserStatus.Online;
                        OnContactListReceiveEvent.Invoke(null, contactListData);
                    }
                    string allowList = this.iMsnSoap.GetAllowList(this.iTicketData);

                    SendData("BLP " + iTransactID + " AL\r\n", iMainSocketWrapper);
                    SendData("ADL " + iTransactID + " " + allowList.Length + "\r\n" + allowList, iMainSocketWrapper);

                    SendData("PRP " + iTransactID + " MFN NickName\r\n", iMainSocketWrapper);

                    SendData("CHG " + iTransactID + " NLN 2789003308:48\r\n", iMainSocketWrapper);

                    String sentString = "<EndpointData><Capabilities>2789003308:48</Capabilities></EndpointData>";
                    SendData("UUX " + iTransactID + " " + sentString.Length + "\r\n" + sentString, iMainSocketWrapper);

                    sentString = "<PrivateEndpointData><EpName>NickName</EpName><Idle>false</Idle><ClientType>1</ClientType><State>NLN</State></PrivateEndpointData>";
                    SendData("UUX " + iTransactID + " " + sentString.Length + "\r\n" + sentString, iMainSocketWrapper);

                    sentString = "<Data><PSM></PSM><CurrentMedia></CurrentMedia></Data>";
                    this.SendData("UUX " + iTransactID + " " + sentString.Length + "\r\n" + sentString, iMainSocketWrapper);
                    aSocketWrapper.lastCommand = Commands.NONE;

                    /*
                    
                    aSocketWrapper.lastCommand = Commands.NONE;
                    SendData("CHG " + iTransactID + " NLN 0\r\n", iMainSocketWrapper);
                      * */
                }
                else if (MSNClient_Data.GetContentType(aSocketWrapper.iDataReceive) == "text/plain;")
                {
                    MessageData messageData = MessageData.GetMessage(aSocketWrapper.iDataReceive);
                    OnMessageReceiveEvent.Invoke(null, messageData);
                }
            }
            else if (aSocketWrapper.lastCommand == Commands.CHL)
            {
                if (aSocketWrapper.iDataReceive.Split(new char[] { ' ' }).Length == 3)
                {
                    String chlNumber = aSocketWrapper.iDataReceive.Split(new char[] { ' ' })[2].TrimEnd();
                    iDataSend = "QRY "+iTransactID+" "+MD5_Digets.ProductID+" 32\r\n"+MD5_Digets.BuildChallenge(chlNumber);
                    SendData(iDataSend, iMainSocketWrapper);
                }
            }
            /*
             * UBX accountName@domain.com 1 118
             * 118 is data length cn be 0
             * after UBX data can be another comand
             */
            else if (aSocketWrapper.lastCommand == Commands.UBX)
            {
                try
                {
                    Process_UBX(aSocketWrapper.iDataReceive);
                }
                catch (Exception e)
                {
                    Console.WriteLine("Error Processing UBX: " + e.StackTrace);
                    Console.WriteLine("\r\nData:" + aSocketWrapper.iDataReceive + "\r\n");
                }
            }
            else if (aSocketWrapper.lastCommand == Commands.RNG)
            {
                SocketWrapper msgSocketWrapper = new SocketWrapper(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                if (GetIPFromCommand(aSocketWrapper.lastCommand, aSocketWrapper.iDataReceive) != IPAddress.None)
                {
                    iOpenedSessions.Add(msgSocketWrapper);
                    Console.WriteLine("RNG ->" + GetIPFromCommand(aSocketWrapper.lastCommand, aSocketWrapper.iDataReceive).ToString());
                    msgSocketWrapper.socket.Connect(GetIPFromCommand(aSocketWrapper.lastCommand, aSocketWrapper.iDataReceive), iMsnPort);
                    msgSocketWrapper.state = SocketState.Connected;
                    msgSocketWrapper.accountName = aSocketWrapper.iDataReceive.Split(' ')[5];
                    Console.WriteLine("Account Name:" + msgSocketWrapper.accountName);
                    msgSocketWrapper.socket.BeginReceive(msgSocketWrapper.iReceiveBuffer, 0, msgSocketWrapper.Buffer_Size, SocketFlags.None, DataReceived_Callback, msgSocketWrapper);
                    String data = String.Format("ANS {0} {1} {2} {3}\r\n", iTransactID, iLogin, aSocketWrapper.iDataReceive.Split(' ')[4], aSocketWrapper.iDataReceive.Split(' ')[1]);
                    SendData(data, msgSocketWrapper);
                }
            }
            else if (aSocketWrapper.lastCommand == Commands.BYE)
            {
                Console.WriteLine("Server:" + aSocketWrapper.iDataReceive);
                Console.WriteLine("Bye!");
                if (iOpenedSessions.Contains(aSocketWrapper))
                {

                    aSocketWrapper.state = SocketState.Disconnected;
                    aSocketWrapper.socket.Close();
                    iOpenedSessions.Remove(aSocketWrapper);
                }
            }
            else if (aSocketWrapper.lastCommand == Commands.NLN | aSocketWrapper.lastCommand == Commands.ILN | aSocketWrapper.lastCommand == Commands.FLN)
            {
                Process_ILN_NLN_FLN(aSocketWrapper.iDataReceive, aSocketWrapper.lastCommand);
            }
            else if (aSocketWrapper.lastCommand == Commands.JOI)
            {
                SendData(dataToSend, userToJoin);
            }

        }

        /*
         * UBX accountName@domain.com 1 118\r\n{data with size of 118 bytes}\r\n
         * 118 is data length can be 0
         * after UBX data can be another comand
         */
        public void Process_UBX(String data)
        {
            /*
            UserStatusInfo info = new UserStatusInfo();
            //Sending notification            
            String[] ubxData = data.Split(new string[] { "\r\n" }, StringSplitOptions.None);
            int dataLength = 0;
            for (int i = 0; i < ubxData.Length - 1; i++)
            {
                Console.WriteLine("\n" + ubxData[i] + "\n");
                //Account name
                info.accountName = ubxData[i].Split(' ')[1];
                dataLength = int.Parse(ubxData[i].Split(' ')[3]);

                if (ubxData[i + 1].Length > dataLength)
                {
                    String additionalData = ubxData[i + 1].Substring(dataLength);
                    Commands cmd = GetNewCommand(additionalData);
                    i++;
                    if (cmd == Commands.UBX)
                    {
                        Process_UBX(additionalData + "\r\n" + ubxData[i + 1]);
                        i++;
                    }
                    else if (cmd == Commands.ILN || cmd == Commands.NLN || cmd == Commands.FLN)
                    {
                        Process_ILN_NLN_FLN(additionalData, cmd);
                    }

                }
                //Here we need process ubx data :)
                //<Data><PSM>:)@Brighton</PSM><CurrentMedia></CurrentMedia><MachineGuid>{AE6A4E33-96FE-4E6C-BCF8-8F47C498EB77}</MachineGuid></Data>
                if (dataLength > 0)
                {
                    i++;
                    String dataUbx = ubxData[i].Substring(0, dataLength);
                    String tag_name = dataUbx.Substring(0, dataUbx.IndexOf("</PSM>"));
                    tag_name = tag_name.Substring(tag_name.LastIndexOf(">") + 1);
                    info.tagName = tag_name;
                }
            }
            OnUserInfoUpdateEvent.Invoke(null, info);
             * */

            string[] ubxData = data.Split(new string[] { "\r\n" }, StringSplitOptions.None);
            int startIndex = 0;
            for (int i = 0; i < (ubxData.Length - 1); i++)
            {
                Console.WriteLine("\n" + ubxData[i] + "\n");
                startIndex = int.Parse(ubxData[i].Split(new char[] { ' ' })[3]);
                if (ubxData[i + 1].Length > startIndex)
                {
                    string aDataReceive = ubxData[i + 1].Substring(startIndex);
                    Commands newCommand = GetNewCommand(aDataReceive);
                    i++;
                    switch (newCommand)
                    {
                        case Commands.UBX:
                            this.Process_UBX(aDataReceive + "\r\n" + ubxData[i + 1]);
                            i++;
                            break;
                        case Commands.ILN:
                        case Commands.NLN:
                        case Commands.FLN:
                            this.Process_ILN_NLN_FLN(aDataReceive, newCommand);
                            break;
                    }
                }
                else
                {
                    i++;
                }
            }


        }
        public void Process_ILN_NLN_FLN(String data, Commands aCmd)
        {
            UserStatusInfo info = new UserStatusInfo();
            if (data.Split(new string[] { "\r\n" }, StringSplitOptions.None).Length > 1)
            {
                String[] commandData = data.Split(new string[] { "\r\n" }, StringSplitOptions.None);
                data = commandData[0];
                for (int i = 1; i < commandData.Length - 1; i++)
                {
                    Commands cmd = GetNewCommand(commandData[i]);
                    if (cmd == Commands.UBX)
                    {
                        Process_UBX(commandData[i] + "\r\n" + commandData[i + 1]);
                        i++;
                    }
                    else if (cmd == Commands.ILN || cmd == Commands.NLN || cmd == Commands.FLN)
                    {
                        Process_ILN_NLN_FLN(commandData[i], cmd);
                    }
                }

            }
            /*
             * NLN NLN mastahh@gmail.com 1 Mastahh 1985855532
             */
            if (aCmd == Commands.NLN)
            {
                info.userStatus = UserStatusInfo.UserStatusFromString(data.Split(' ')[1]);
                info.accountName = data.Split(' ')[2];
                info.displayName = System.Web.HttpUtility.UrlDecode(data.Split(' ')[4]);
            }
            /*
             * ILN 8 BSY accountname@gmail.com 1 NickName
             */
            else if (aCmd == Commands.ILN)
            {
                info.userStatus = UserStatusInfo.UserStatusFromString(data.Split(' ')[2]);
                info.accountName = data.Split(' ')[3];
                info.displayName = System.Web.HttpUtility.UrlDecode(data.Split(' ')[5]);

            }
            /*
             * FLN accountname@gmail.com 1 0
             */
            else if (aCmd == Commands.FLN)
            {
                info.accountName = data.Split(' ')[1];
                info.userStatus = UserStatus.Offline;
            }
            //Sending notification
            OnUserInfoUpdateEvent.Invoke(null, info);

        }

        #region GetMSNAuth()
        private String GetMSPAuth(String data)
        {
            String MSPAuth = "MSPAuth:";
            int index = data.IndexOf(MSPAuth);//MSPAuth section
            if (index > 0)
            {
                return data.Substring(index, data.IndexOf("\r\n", index + 1) - index).Split(' ')[1];
            }
            return "";

        }
        #endregion

        #region GetIPFromCommand() For XFR COmmand
        private IPAddress GetIPFromCommand(Commands aLastCommand, string aDataReceive)
        {
            /*
             * Getting first ip from string 
             * XFR 3 NS 207.46.107.95:1863 U D\r\n
             * if will be 207.46.107.95
             */
            if (aLastCommand == Commands.XFR)
            {
                return IPAddress.Parse(aDataReceive.Split(' ')[3].Split(':')[0]);
            }
            else if (aLastCommand == Commands.RNG)
            {
                return IPAddress.Parse(aDataReceive.Split(' ')[2].Split(':')[0]);
            }
            return IPAddress.None;

        }
        #endregion

        #region CallBack Function for received data
        protected void DataReceived_Callback(IAsyncResult result)
        {
            SocketWrapper resSocketWrapper = (SocketWrapper)result.AsyncState;
            if (resSocketWrapper.state == SocketState.Connected)
            {
                try
                {
                    int n = resSocketWrapper.socket.EndReceive(result);
                    if (n > 0)
                    {
                        if (resSocketWrapper.socket.Available == 0)
                        {
                            Console.WriteLine("Received:{0}", n);
                        }
                        else
                        {
                            Console.WriteLine("Received:{0}, Avaliable:{1}", n, resSocketWrapper.socket.Available);
                        }
                        resSocketWrapper.iDataReceive = Encoding.UTF8.GetString(resSocketWrapper.iReceiveBuffer, 0, n);
                        Commands newCommand = GetNewCommand(resSocketWrapper.iDataReceive); //Setting command that was Receive.
                        if (newCommand != Commands.NONE)
                        {
                            resSocketWrapper.lastCommand = newCommand;
                        }
                        if ((newCommand == Commands.NONE) && (resSocketWrapper.lastCommand != Commands.GCF))
                        {
                            Console.WriteLine("Server NONE:" + resSocketWrapper.iDataReceive);
                        }
                        if (IsAllDataReceive(resSocketWrapper))
                        {
                            Console.WriteLine("\nServer:" + resSocketWrapper.iDataReceive.Replace("\r\n", "\n(|r|n|)\n"));
                        }
                        ProcessReceiveData(resSocketWrapper);
                        if (resSocketWrapper.state == SocketState.Connected)
                        {
                            resSocketWrapper.socket.BeginReceive(resSocketWrapper.iReceiveBuffer, 0, resSocketWrapper.Buffer_Size, SocketFlags.None, DataReceived_Callback, resSocketWrapper);
                        }

                    }
                }
                catch (SocketException se)
                {
                    Console.WriteLine(se.Message);
                    Console.WriteLine("Socket DataRecieve error: " + se.NativeErrorCode);
                    resSocketWrapper.state = SocketState.Disconnected;
                    resSocketWrapper.socket.Close();
                }
                catch (Exception e)
                {
                    Console.WriteLine("DataRecieve Error: " + e.Message);
                    Console.WriteLine(e.StackTrace);
                }
            }

        }
        #endregion

        private SocketWrapper GetSocketWrapperObject(String aAccountName)
        {
            for (int i = 0; i < iOpenedSessions.Count; i++)
            {
                if (((SocketWrapper)iOpenedSessions[i]).accountName == aAccountName.ToLower())
                {
                    return (SocketWrapper)iOpenedSessions[i];
                }

            }
            return null;

        }
        /*
         * Checker for some commands where can be a lot of data and that can be sent in two or more packeges
         */

        private bool IsAllDataReceive(SocketWrapper aSocketWrapper)
        {
            if (aSocketWrapper.lastCommand == Commands.GCF)
            {
                iAllDataReceived = false;

                if (aSocketWrapper.iDataReceive.Substring(0, 3) == "GCF")
                {
                    Console.WriteLine("Server:" + aSocketWrapper.iDataReceive.Substring(0, aSocketWrapper.iDataReceive.IndexOf("\r\n")).TrimEnd());
                    iLargeDataSize = int.Parse(aSocketWrapper.iDataReceive.Substring(0, aSocketWrapper.iDataReceive.IndexOf("\r\n")).Split(' ')[2]);
                    iLargeDataStore += aSocketWrapper.iDataReceive.Substring(aSocketWrapper.iDataReceive.IndexOf("\r\n") + 2);
                    return iAllDataReceived;
                }

                else if (iLargeDataSize > 0)
                {
                    iLargeDataStore += aSocketWrapper.iDataReceive;
                    if (aSocketWrapper.iDataReceive.Contains("USR "))
                    {
                        aSocketWrapper.iDataReceive = aSocketWrapper.iDataReceive.Substring(aSocketWrapper.iDataReceive.IndexOf("USR"));
                        Commands newCommand = GetNewCommand(aSocketWrapper.iDataReceive);
                        if (newCommand != Commands.NONE)
                        {
                            aSocketWrapper.lastCommand = newCommand;
                        }
                    }

                    if (iLargeDataStore.Length == iLargeDataSize || iLargeDataStore.Length > iLargeDataSize)
                    {

                        if (WriteDebugDataToFile)
                        {
                            WriteToFile("C:\\Documents and Settings\\" + Environment.UserName + "\\Desktop\\Msn_Client_Debug_Data\\msn.xml", iLargeDataStore.Substring(0, iLargeDataSize));
                        }
                        iAllDataReceived = true;
                        iLargeDataStore = "";
                        iLargeDataSize = 0;
                    }
                }
            }
            return iAllDataReceived;
        }
        public bool IsLoggedIn()
        {
            if (this.iMainSocketWrapper == null)
            {
                return false;
            }
            return this.iMainSocketWrapper.IsConnected();
        }

        public void LogOut()
        {
            Console.WriteLine("Logging Out...");
            this.CloseMessageSessions();
            if (this.iMainSocketWrapper != null)
            {
                this.SendData("OUT \r\n", this.iMainSocketWrapper);
                this.Disconnect();
            }
        }

        public void Disconnect()
        {
            if (iOpenedSessions.Count > 0)
            {
                for (int i = 0; i < iOpenedSessions.Count; i++)
                {
                    SocketWrapper sockWrapper = (SocketWrapper)iOpenedSessions[i];
                    sockWrapper.state = SocketState.Disconnected;
                    sockWrapper.socket.Close();
                    iOpenedSessions.RemoveAt(i);
                }
            }
            if (iMainSocketWrapper != null)
            {
                IAsyncResult asyncResult = this.iMainSocketWrapper.socket.BeginDisconnect(true, null, null);
                this.iMainSocketWrapper.socket.EndDisconnect(asyncResult);


                iMainSocketWrapper.state = SocketState.Disconnected;
                iMainSocketState = SocketState.Disconnected;
                OnStateChangedEvent.Invoke(this, EventArgs.Empty);
                iMainSocketWrapper.socket.Close();
            }
            Console.WriteLine("Disconnected!");
        }
        /*
         * 
         * Set Login Name
         * Format must be alredy correct ****@***.***
         * 
         * */
        private Commands GetNewCommand(String aDataReceive)
        {

            /*
             * If no new command in list then last command will  NONE
             */
            if (aDataReceive.Length > 3)
            {
                if (aDataReceive.Substring(0, 3) == "CVR")
                    return Commands.CVR;
                else if (aDataReceive.Substring(0, 3) == "GCF")
                    return Commands.GCF;
                else if (aDataReceive.Substring(0, 3) == "USR")
                    return Commands.USR;
                else if (aDataReceive.Substring(0, 3) == "VER")
                    return Commands.VER;
                else if (aDataReceive.Substring(0, 3) == "XFR")
                    return Commands.XFR;
                else if (aDataReceive.Substring(0, 3) == "SBS")
                    return Commands.SBS;
                else if (aDataReceive.Substring(0, 3) == "MSG")
                    return Commands.MSG;
                else if (aDataReceive.Substring(0, 3) == "CHL")
                    return Commands.CHL;
                else if (aDataReceive.Substring(0, 3) == "UBX")
                    return Commands.UBX;
                else if (aDataReceive.Substring(0, 3) == "RNG")
                    return Commands.RNG;
                else if (aDataReceive.Substring(0, 3) == "BYE")
                    return Commands.BYE;
                else if (aDataReceive.Substring(0, 3) == "ANS")
                    return Commands.ANS;
                else if (aDataReceive.Substring(0, 3) == "IRO")
                    return Commands.IRO;
                else if (aDataReceive.Substring(0, 3) == "FLN")
                    return Commands.FLN;
                else if (aDataReceive.Substring(0, 3) == "NLN")
                    return Commands.NLN;
                else if (aDataReceive.Substring(0, 3) == "ILN")
                    return Commands.ILN;
                else if (aDataReceive.Substring(0, 3) == "JOI")
                    return Commands.JOI;
                else if (aDataReceive.Substring(0, 3) == "ACK")
                    return Commands.ACK;
                else if (aDataReceive.Substring(0, 3) == "CAL")
                    return Commands.CAL;
                else if (aDataReceive.Substring(0, 3) == "QRY")
                    return Commands.QRY;

                else if (aDataReceive.Split(' ').Length == 2)
                {
                    int error = 0;
                    if (int.TryParse(aDataReceive.Split(' ')[0], out error))
                    {
                        Console.WriteLine("Error on connection:{0}({1})", error, aDataReceive.Split(' ')[1].TrimEnd());
                        Disconnect();
                    }
                }
            }
            return Commands.NONE;

        }
        public String Login
        {
            get { return iLogin; }
            set { iLogin = value; }
        }
        /*
         * TODO: Store password as MD5(sucks) better something else
         * 
         */
        public String Password
        {
            get { return iPassword; }
            set { iPassword = value; }
        }
        protected virtual void OnStateChanged(object sender, EventArgs e)
        {
            MsnClient obj = (MsnClient)sender;
            Console.WriteLine("OnStateChangedEvent" + obj.iMainSocketWrapper.state);

        }

        /*
         * 
         * 
         * For Temp Use
         */
        public static void WriteToFile(String fileName, String dataToWrite)
        {
            try
            {
                Directory.CreateDirectory(fileName.Substring(0, fileName.LastIndexOf('\\')));
                StreamWriter sw = new StreamWriter(fileName);
                sw.Write(dataToWrite);
                sw.Close();
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
        }
    }
}


